package MyScanner;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class C_CodeScanner implements CodeScanner {

    private final String srcPath;
    private final String[] src;
    private final DFA CDfa;
    private int curRowIndex;
    private int curColIndex;

    private int forePointer;
    private int backPointer;

    private TokensBlock tokensBlock;

    public C_CodeScanner(String srcPath)
    {
        this.srcPath = srcPath;
        src = readFile(srcPath);
        curColIndex = 0;
        curRowIndex = 0;
        CDfa = new DFA();
    }

    @Override
    public void run()
    {
        forePointer = 0;
        backPointer = 0;

        tokensBlock = new TokensBlock(srcPath);
        for(int i = 1; i <= src.length; i++)
        {
            curRowIndex = i;
            rowAnalyse(src[i-1]);
        }
        curRowIndex += 1;
        curColIndex = 0;
    }


    private void rowAnalyse(String code)
    {
        StringBuilder tokenContent = new StringBuilder();
        curColIndex = 0;
        for(int i = 0; i < code.length(); i++)
        {
            char curCh = code.charAt(i);
            if(CDfa.getCurState() == DFA.STATE.BACK)
                curCh = '\0';
            curColIndex = i;
            CDfa.stateTransition(curCh, tokenContent.toString());

            if(CDfa.isEndState() && CDfa.getCurState() != DFA.STATE.NULL && CDfa.getCurState() != DFA.STATE.EOF)    //转移后达到终止态
            {
                backPointer -= 1;
                i--;    //需要回退一次重新确认状态

                //1、添加token
                Token.TokenTypes type = Token.mappingDFAEndStateToTokenType(CDfa.getCurState());
                Token token = new Token(tokenContent.toString(), type, tokensBlock.getTokensSize(), forePointer, backPointer, curRowIndex, curColIndex - (backPointer - forePointer) - 1 );
                tokensBlock.addToken(token);
                //System.out.println(token.toString());

                //2、重置变量
                tokenContent = new StringBuilder();
                forePointer = backPointer + 1;
                CDfa.initDFA();
            }
            else if(CDfa.isEndState() && CDfa.getCurState() == DFA.STATE.EOF)
            {
                backPointer -= 1;
                Token.TokenTypes type = Token.mappingDFAEndStateToTokenType(CDfa.getCurState());
                Token token = new Token("<EOF>", type, tokensBlock.getTokensSize(), forePointer, backPointer, curRowIndex, curColIndex - (backPointer - forePointer) - 1 );
                tokensBlock.addToken(token);
                CDfa.initDFA();
            }
            else if(CDfa.isEndState() && CDfa.getCurState() == DFA.STATE.NULL)
            {
                forePointer = backPointer + 1;
                CDfa.initDFA();
            }
            else if(CDfa.getCurState() == DFA.STATE.BACK)
            {
                tokenContent.deleteCharAt(tokenContent.length()-1);  //回退
                backPointer -= 2;
                i -= 2;    //需要回退一次重新确认状态
            }
            else {
                tokenContent.append(curCh);
            }

            backPointer += 1;
        }
    }

    //文件读取，为了能够获取到最后的换行符，行首符，只能使用这种方式。
    public String[] readFile(String fPath)
    {
        List<String> strList = new ArrayList<>();
        FileInputStream in = null;
        StringBuilder strb = new StringBuilder();
        try{
            in =new FileInputStream(fPath);
        }catch(FileNotFoundException e) {
            System.out.println("can not find it");
            System.exit(1);
        }
        try{
            int cur = 0;
            while((cur = in.read()) != -1){
                strb.append((char)cur);
                if((char)cur == '\n') {
                    strList.add(strb.toString());
                    strb = new StringBuilder();
                }
            }
            strList.add("\u001a");
        }catch(IOException e) {
            e.printStackTrace();
        }
        String[] srcArray = new String[strList.size()];
        for(int i = 0; i < strList.size(); i++) {
            srcArray[i] = strList.get(i);
        }
        return srcArray;
    }

    public String[] getTokensArray()
    {
        Token[] tokens = tokensBlock.getTokens();
        String[] array = new String[tokens.length];
        for(int i = 0; i < tokens.length; i++)
        {
            array[i] = tokens[i].toString();
        }
        return array;
    }
}
